package com.lhf.fvscore.result.advice;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lhf.fvscommon.result.Result;
import com.lhf.fvscommon.result.Status;
import com.lhf.fvscore.annotation.ResultBody;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;

/**
 * <p>
 * 统一返回处理 {@link ResultBody}
 * </p>
 *
 * @author lhf
 * @since 2020/11/6 14:30
 */
@ControllerAdvice(annotations = {ResultBody.class})
public class ResultAdvice implements ResponseBodyAdvice<Object> {

    private final ThreadLocal<ObjectMapper> mapperThreadLocal = ThreadLocal.withInitial(ObjectMapper::new);

    private static final Class[] annos = {
            RequestMapping.class,
            GetMapping.class,
            PostMapping.class,
            DeleteMapping.class,
            PutMapping.class,
            PatchMapping.class
    };

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return this.validateMethod(methodParameter);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest request, ServerHttpResponse response) {


        Object out;
        ObjectMapper mapper = mapperThreadLocal.get();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        //默认返回状态码
        int code = Status.SUCCESS.code;
        //默认返回的错误信息
        String mes = Status.SUCCESS.mes;

        AnnotatedElement element = methodParameter.getAnnotatedElement();
        ResultBody annotation = element.getAnnotation(ResultBody.class);
        if (annotation != null) {
            int code1 = annotation.code();
            String mes1 = annotation.mes();

            if (code1 != 0) {
                code = code1;

            } else {
                code = annotation.status().code;
            }
            if (StringUtils.isNoneBlank(mes)) {
                mes = mes1;
            } else {
                mes = annotation.status().mes;
            }
        }

        if (body instanceof Result) {
            out = body;
        } else if (body instanceof CharSequence) {
            Result<Object> result = new Result<>(code, body, mes);
            try {
                out = mapper.writeValueAsString(result);
            } catch (JsonProcessingException e) {
                out = Result.failure();
            }
        } else {
            out = new Result<>(code, body, mes);
        }
        return out;

    }

    /**
     * 验证方法是否是 {@link RequestMapping,GetMapping,PostMapping,DeleteMapping,PutMapping,PatchMapping} 修饰的类
     *
     * @param methodParameter
     * @return
     */
    private boolean validateMethod(MethodParameter methodParameter) {
        AnnotatedElement element = methodParameter.getAnnotatedElement();
        return Arrays.stream(annos).anyMatch(anno -> anno.isAnnotation() && element.isAnnotationPresent(anno));
    }

    private boolean validateClass(Class<Object> aClass) {
        return aClass.isAnnotationPresent(ResultBody.class);
    }
}
